﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ExcelAddIn1
{
    class Forecasting_WeightedMovingAverage : Test
    {
        public Forecasting_WeightedMovingAverage(DataContainer data)
        {
            this.data = data;
            res = new List<String>();
        }

        public override string GetInfo()
        {
            String s = "Forecasts a dataset using Weighted Moving Average with 3 periods and weights {1.6, 1.2, 1.0}.";
            return s;
        }

        //The weights to use
        private double[] weights = { 1.0, 1.2, 1.6 };

        public override void RunTest()
        {
            res.Add("Weighted Moving Average");

            //Error check
            if (data.GetNoSets() != 1)
            {
                res.Add("One dataset is required!");
                return;
            }

            DataSet d = data.GetDataSet(0);

            //Error check 2
            if (d.GetN() < 4)
            {
                res.Add("Sample size of minimum 4 is required!");
                return;
            }

            res.Add("Periods;Forecast;MSE;-");
            double Fc = CalcFc(3, d);
            double MSE = CalcMSE(3, d);
            res.Add("3;" + Fc.ToString("F2") + ";" + MSE.ToString("F2"));
            
            res.Add(";;;-");
        }

        private double CalcFc(int periods, DataSet d)
        {
            return CalcFc(periods, d.GetN(), d);
        }

        private double CalcFc(int periods, int row, DataSet d)
        {
            double sumW = 0.0;
            double Fc = 0.0;
            int wi = weights.Length - periods;

            for (int r = row - periods; r < row; r++)
            {
                double w = weights[wi];
                Fc += d.GetValue(r) * w;
                sumW += w;
                wi++;
            }

            Fc = Fc / sumW;

            return Fc;
        }

        private double CalcMSE(int periods, DataSet d)
        {
            //Create table
            double[,] tab = new double[d.GetN(), 4];
            for (int r = 0; r < d.GetN(); r++)
            {
                //Actual
                tab[r, 0] = d.GetValue(r);
                if (r >= periods)
                {
                    //Forecast
                    tab[r, 1] = CalcFc(periods, r, d);
                    //Error
                    tab[r, 2] = tab[r, 0] - tab[r, 1];
                    //Absolute error
                    tab[r, 3] = Math.Pow(tab[r, 2], 2);
                }
            }

            //Calculate Mean Squared Error
            double MSE = 0.0;
            int n = 0;
            for (int r = periods; r < d.GetN(); r++)
            {
                MSE += tab[r, 3];
                n++;
            }
            MSE = MSE / (double)n;

            return MSE;
        }
    }
}
